/**
 * demo_plugin.c - 钩子框架演示插件
 *
 * 这个插件提供了一个完整的钩子框架插件实现示例，
 * 包含各种类型钩子的回调实现。
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>

#include "../../include/hook_framework.h"

/* 插件配置 */
typedef struct {
    int log_level;             /* 日志级别 */
    char log_file[256];        /* 日志文件路径 */
    int monitor_file_ops;      /* 是否监控文件操作 */
    int monitor_network_ops;   /* 是否监控网络操作 */
    int monitor_process_ops;   /* 是否监控进程操作 */
    int monitor_memory_ops;    /* 是否监控内存操作 */
    char sensitive_files[10][256]; /* 敏感文件列表 */
    int sensitive_file_count;  /* 敏感文件数量 */
    char blocked_hosts[10][256]; /* 禁止连接的主机列表 */
    int blocked_host_count;    /* 禁止主机数量 */
} plugin_config_t;

/* 全局插件配置 */
static plugin_config_t g_config = {
    .log_level = LOG_INFO,
    .log_file = "/tmp/demo_plugin.log",
    .monitor_file_ops = 1,
    .monitor_network_ops = 1,
    .monitor_process_ops = 1,
    .monitor_memory_ops = 1,
    .sensitive_files = {
        "/etc/passwd",
        "/etc/shadow",
        "/etc/ssl/private"
    },
    .sensitive_file_count = 3,
    .blocked_hosts = {
        "192.168.1.100",
        "10.0.0.1",
        "evil.example.com"
    },
    .blocked_host_count = 3
};

/* 统计数据 */
typedef struct {
    pthread_mutex_t lock;      /* 互斥锁 */
    unsigned long file_opens;  /* 文件打开次数 */
    unsigned long file_reads;  /* 文件读取次数 */
    unsigned long file_writes; /* 文件写入次数 */
    unsigned long connections; /* 网络连接次数 */
    unsigned long sends;       /* 数据发送次数 */
    unsigned long recvs;       /* 数据接收次数 */
    unsigned long execs;       /* 进程执行次数 */
    unsigned long allocs;      /* 内存分配次数 */
    unsigned long frees;       /* 内存释放次数 */
    unsigned long blocked_ops; /* 被阻止的操作次数 */
} plugin_stats_t;

/* 全局统计数据 */
static plugin_stats_t g_stats = {
    .lock = PTHREAD_MUTEX_INITIALIZER,
    .file_opens = 0,
    .file_reads = 0,
    .file_writes = 0,
    .connections = 0,
    .sends = 0,
    .recvs = 0,
    .execs = 0,
    .allocs = 0,
    .frees = 0,
    .blocked_ops = 0
};

/* ===== 辅助函数 ===== */

/**
 * 记录消息到插件日志文件
 */
static void plugin_log(int level, const char* format, ...) {
    /* 检查日志级别 */
    if (level > g_config.log_level) {
        return;
    }

    /* 获取时间戳 */
    time_t now = time(NULL);
    char timestamp[64];
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", localtime(&now));

    /* 格式化消息 */
    va_list args;
    va_start(args, format);
    char message[1024];
    vsnprintf(message, sizeof(message), format, args);
    va_end(args);

    /* 获取级别名称 */
    const char* level_name = "UNKNOWN";
    switch (level) {
        case LOG_ERROR: level_name = "ERROR"; break;
        case LOG_WARN:  level_name = "WARN"; break;
        case LOG_INFO:  level_name = "INFO"; break;
        case LOG_DEBUG: level_name = "DEBUG"; break;
    }

    /* 打开日志文件 */
    FILE* fp = fopen(g_config.log_file, "a");
    if (fp) {
        fprintf(fp, "[%s] [%s] %s\n", timestamp, level_name, message);
        fclose(fp);
    }

    /* 同时输出到标准错误 */
    if (level <= LOG_INFO) {
        fprintf(stderr, "[DEMO-PLUGIN] [%s] %s\n", level_name, message);
    }
}

/**
 * 检查文件是否敏感
 */
static int is_sensitive_file(const char* path) {
    if (!path) return 0;

    for (int i = 0; i < g_config.sensitive_file_count; i++) {
        if (strstr(path, g_config.sensitive_files[i])) {
            return 1;
        }
    }
    return 0;
}

/**
 * 检查主机是否被禁止
 */
static int is_blocked_host(const char* host) {
    if (!host) return 0;

    for (int i = 0; i < g_config.blocked_host_count; i++) {
        if (strcmp(host, g_config.blocked_hosts[i]) == 0 ||
            strstr(host, g_config.blocked_hosts[i])) {
            return 1;
        }
    }
    return 0;
}

/**
 * 更新插件统计数据
 */
static void update_stats(unsigned long* counter) {
    pthread_mutex_lock(&g_stats.lock);
    (*counter)++;
    pthread_mutex_unlock(&g_stats.lock);
}

/**
 * 记录拦截操作
 */
static void log_blocked_operation(const char* operation, const char* reason) {
    plugin_log(LOG_WARN, "拦截操作: %s, 原因: %s", operation, reason);
    update_stats(&g_stats.blocked_ops);
}

/**
 * 记录访问统计
 */
static void log_statistics() {
    pthread_mutex_lock(&g_stats.lock);
    plugin_log(LOG_INFO, "统计数据:");
    plugin_log(LOG_INFO, "  文件打开次数: %lu", g_stats.file_opens);
    plugin_log(LOG_INFO, "  文件读取次数: %lu", g_stats.file_reads);
    plugin_log(LOG_INFO, "  文件写入次数: %lu", g_stats.file_writes);
    plugin_log(LOG_INFO, "  网络连接次数: %lu", g_stats.connections);
    plugin_log(LOG_INFO, "  数据发送次数: %lu", g_stats.sends);
    plugin_log(LOG_INFO, "  数据接收次数: %lu", g_stats.recvs);
    plugin_log(LOG_INFO, "  进程执行次数: %lu", g_stats.execs);
    plugin_log(LOG_INFO, "  内存分配次数: %lu", g_stats.allocs);
    plugin_log(LOG_INFO, "  内存释放次数: %lu", g_stats.frees);
    plugin_log(LOG_INFO, "  被阻止的操作: %lu", g_stats.blocked_ops);
    pthread_mutex_unlock(&g_stats.lock);
}

/* ===== 文件操作回调 ===== */

/**
 * open 前置回调
 */
static int open_pre_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_file_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    const char* path = (const char*)context->args[0];
    int flags = (int)(long)context->args[1];

    /* 记录文件操作 */
    char mode_str[32] = {0};
    if ((flags & O_ACCMODE) == O_RDONLY) strcat(mode_str, "只读");
    if ((flags & O_ACCMODE) == O_WRONLY) strcat(mode_str, "只写");
    if ((flags & O_ACCMODE) == O_RDWR) strcat(mode_str, "读写");
    if (flags & O_CREAT) strcat(mode_str, "|创建");
    if (flags & O_TRUNC) strcat(mode_str, "|截断");
    if (flags & O_APPEND) strcat(mode_str, "|追加");

    plugin_log(LOG_INFO, "打开文件: %s (模式: %s)", path, mode_str);

    /* 检查敏感文件 */
    if (is_sensitive_file(path)) {
        plugin_log(LOG_WARN, "尝试访问敏感文件: %s", path);
        
        /* 设置上下文标志 */
        set_context_flag(context, CTX_FLAG_BLOCKED);
        log_blocked_operation("open", "敏感文件访问");
        
        /* 设置errno为权限拒绝 */
        errno = EACCES;
        return HOOK_ABORT;  /* 拦截操作 */
    }

    return HOOK_CONTINUE;  /* 允许操作继续 */
}

/**
 * open 后置回调
 */
static int open_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_file_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    const char* path = (const char*)context->args[0];
    int fd = (int)(long)context->result;

    if (fd >= 0) {
        plugin_log(LOG_DEBUG, "文件打开成功: %s (fd=%d)", path, fd);
        update_stats(&g_stats.file_opens);
    } else {
        plugin_log(LOG_DEBUG, "文件打开失败: %s (errno=%d)", path, errno);
    }

    return HOOK_CONTINUE;
}

/**
 * read 回调
 */
static int read_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_file_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    int fd = (int)(long)context->args[0];
    void* buf = context->args[1];
    size_t count = (size_t)(long)context->args[2];
    ssize_t result = (ssize_t)(long)context->result;

    if (result > 0) {
        plugin_log(LOG_DEBUG, "读取文件: fd=%d, 字节数=%zd", fd, result);
        update_stats(&g_stats.file_reads);
    }

    return HOOK_CONTINUE;
}

/**
 * write 回调
 */
static int write_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_file_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    int fd = (int)(long)context->args[0];
    const void* buf = context->args[1];
    size_t count = (size_t)(long)context->args[2];
    ssize_t result = (ssize_t)(long)context->result;

    if (result > 0) {
        plugin_log(LOG_DEBUG, "写入文件: fd=%d, 字节数=%zd", fd, result);
        update_stats(&g_stats.file_writes);
    }

    return HOOK_CONTINUE;
}

/* ===== 网络操作回调 ===== */

/**
 * connect 前置回调
 */
static int connect_pre_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_network_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    int sockfd = (int)(long)context->args[0];
    const struct sockaddr* addr = (const struct sockaddr*)context->args[1];

    /* 只处理IPv4连接 */
    if (addr && addr->sa_family == AF_INET) {
        const struct sockaddr_in* addr_in = (const struct sockaddr_in*)addr;
        char ip_str[INET_ADDRSTRLEN] = {0};
        inet_ntop(AF_INET, &(addr_in->sin_addr), ip_str, INET_ADDRSTRLEN);
        int port = ntohs(addr_in->sin_port);

        plugin_log(LOG_INFO, "连接到: %s:%d (sockfd=%d)", ip_str, port, sockfd);

        /* 检查是否为禁止的主机 */
        if (is_blocked_host(ip_str)) {
            plugin_log(LOG_WARN, "尝试连接到禁止的主机: %s", ip_str);
            
            /* 设置上下文标志 */
            set_context_flag(context, CTX_FLAG_BLOCKED);
            log_blocked_operation("connect", "禁止的主机");
            
            /* 设置errno为连接拒绝 */
            errno = ECONNREFUSED;
            return HOOK_ABORT;  /* 拦截操作 */
        }
    }

    return HOOK_CONTINUE;  /* 允许操作继续 */
}

/**
 * connect 后置回调
 */
static int connect_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_network_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    int result = (int)(long)context->result;

    if (result == 0) {
        update_stats(&g_stats.connections);
    }

    return HOOK_CONTINUE;
}

/**
 * send/sendto 后置回调
 */
static int send_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_network_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    int sockfd = (int)(long)context->args[0];
    const void* buf = context->args[1];
    size_t len = (size_t)(long)context->args[2];
    ssize_t result = (ssize_t)(long)context->result;

    if (result > 0) {
        plugin_log(LOG_DEBUG, "发送数据: sockfd=%d, 字节数=%zd", sockfd, result);
        update_stats(&g_stats.sends);
    }

    return HOOK_CONTINUE;
}

/**
 * recv/recvfrom 后置回调
 */
static int recv_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_network_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    int sockfd = (int)(long)context->args[0];
    void* buf = context->args[1];
    size_t len = (size_t)(long)context->args[2];
    ssize_t result = (ssize_t)(long)context->result;

    if (result > 0) {
        plugin_log(LOG_DEBUG, "接收数据: sockfd=%d, 字节数=%zd", sockfd, result);
        update_stats(&g_stats.recvs);
    }

    return HOOK_CONTINUE;
}

/* ===== 进程操作回调 ===== */

/**
 * execve 前置回调
 */
static int execve_pre_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_process_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    const char* path = (const char*)context->args[0];
    char* const* argv = (char* const*)context->args[1];

    /* 构建命令行字符串 */
    char cmdline[512] = {0};
    strncpy(cmdline, path, sizeof(cmdline) - 1);

    if (argv) {
        for (int i = 1; argv[i] != NULL && strlen(cmdline) < sizeof(cmdline) - 32; i++) {
            strcat(cmdline, " ");
            strncat(cmdline, argv[i], sizeof(cmdline) - strlen(cmdline) - 1);
        }
    }

    plugin_log(LOG_INFO, "执行程序: %s", cmdline);
    update_stats(&g_stats.execs);

    return HOOK_CONTINUE;
}

/**
 * system 前置回调
 */
static int system_pre_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_process_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    const char* command = (const char*)context->args[0];

    if (command) {
        plugin_log(LOG_INFO, "执行系统命令: %s", command);
        update_stats(&g_stats.execs);
    }

    return HOOK_CONTINUE;
}

/* ===== 内存操作回调 ===== */

/**
 * malloc 后置回调
 */
static int malloc_post_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_memory_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    size_t size = (size_t)(long)context->args[0];
    void* result = context->result;

    if (result) {
        plugin_log(LOG_DEBUG, "内存分配: %zu 字节 -> %p", size, result);
        update_stats(&g_stats.allocs);
    }

    return HOOK_CONTINUE;
}

/**
 * free 前置回调
 */
static int free_pre_callback(void* ctx, void* user_data) {
    if (!g_config.monitor_memory_ops) return HOOK_CONTINUE;

    hook_context_t* context = (hook_context_t*)ctx;
    void* ptr = context->args[0];

    if (ptr) {
        plugin_log(LOG_DEBUG, "内存释放: %p", ptr);
        update_stats(&g_stats.frees);
    }

    return HOOK_CONTINUE;
}

/* ===== 初始化和清理函数 ===== */

/**
 * 读取环境变量配置
 */
static void load_config_from_env() {
    /* 读取日志级别 */
    const char* log_level = getenv("DEMO_PLUGIN_LOG_LEVEL");
    if (log_level) {
        if (strcmp(log_level, "ERROR") == 0) {
            g_config.log_level = LOG_ERROR;
        } else if (strcmp(log_level, "WARN") == 0) {
            g_config.log_level = LOG_WARN;
        } else if (strcmp(log_level, "INFO") == 0) {
            g_config.log_level = LOG_INFO;
        } else if (strcmp(log_level, "DEBUG") == 0) {
            g_config.log_level = LOG_DEBUG;
        }
    }

    /* 读取日志文件路径 */
    const char* log_file = getenv("DEMO_PLUGIN_LOG_FILE");
    if (log_file) {
        strncpy(g_config.log_file, log_file, sizeof(g_config.log_file) - 1);
    }

    /* 读取监控配置 */
    const char* monitor_file = getenv("DEMO_PLUGIN_MONITOR_FILE");
    if (monitor_file) {
        g_config.monitor_file_ops = atoi(monitor_file);
    }

    const char* monitor_network = getenv("DEMO_PLUGIN_MONITOR_NETWORK");
    if (monitor_network) {
        g_config.monitor_network_ops = atoi(monitor_network);
    }

    const char* monitor_process = getenv("DEMO_PLUGIN_MONITOR_PROCESS");
    if (monitor_process) {
        g_config.monitor_process_ops = atoi(monitor_process);
    }

    const char* monitor_memory = getenv("DEMO_PLUGIN_MONITOR_MEMORY");
    if (monitor_memory) {
        g_config.monitor_memory_ops = atoi(monitor_memory);
    }
}

/**
 * 插件初始化函数
 */
__attribute__((visibility("default")))
int plugin_init(void) {
    /* 读取配置 */
    load_config_from_env();

    plugin_log(LOG_INFO, "=== 演示插件初始化 ===");
    plugin_log(LOG_INFO, "插件版本: 1.0.0");
    
    /* 注册文件操作回调 */
    if (g_config.monitor_file_ops) {
        plugin_log(LOG_INFO, "注册文件操作钩子");
        register_function_hook("open", HOOK_TYPE_SYSCALL, HOOK_GROUP_FILE_IO);
        register_pre_callback("open", open_pre_callback, NULL, 100);
        register_post_callback("open", open_post_callback, NULL, 100);

        register_function_hook("read", HOOK_TYPE_SYSCALL, HOOK_GROUP_FILE_IO);
        register_post_callback("read", read_post_callback, NULL, 100);

        register_function_hook("write", HOOK_TYPE_SYSCALL, HOOK_GROUP_FILE_IO);
        register_post_callback("write", write_post_callback, NULL, 100);
    }

    /* 注册网络操作回调 */
    if (g_config.monitor_network_ops) {
        plugin_log(LOG_INFO, "注册网络操作钩子");
        register_function_hook("connect", HOOK_TYPE_SYSCALL, HOOK_GROUP_NETWORK);
        register_pre_callback("connect", connect_pre_callback, NULL, 100);
        register_post_callback("connect", connect_post_callback, NULL, 100);

        register_function_hook("send", HOOK_TYPE_SYSCALL, HOOK_GROUP_NETWORK);
        register_post_callback("send", send_post_callback, NULL, 100);

        register_function_hook("recv", HOOK_TYPE_SYSCALL, HOOK_GROUP_NETWORK);
        register_post_callback("recv", recv_post_callback, NULL, 100);
    }

    /* 注册进程操作回调 */
    if (g_config.monitor_process_ops) {
        plugin_log(LOG_INFO, "注册进程操作钩子");
        register_function_hook("execve", HOOK_TYPE_SYSCALL, HOOK_GROUP_PROCESS);
        register_pre_callback("execve", execve_pre_callback, NULL, 100);

        register_function_hook("system", HOOK_TYPE_LIBRARY, HOOK_GROUP_PROCESS);
        register_pre_callback("system", system_pre_callback, NULL, 100);
    }

    /* 注册内存操作回调 */
    if (g_config.monitor_memory_ops) {
        plugin_log(LOG_INFO, "注册内存操作钩子");
        register_function_hook("malloc", HOOK_TYPE_LIBRARY, HOOK_GROUP_MEMORY);
        register_post_callback("malloc", malloc_post_callback, NULL, 100);

        register_function_hook("free", HOOK_TYPE_LIBRARY, HOOK_GROUP_MEMORY);
        register_pre_callback("free", free_pre_callback, NULL, 100);
    }

    plugin_log(LOG_INFO, "演示插件初始化完成");
    return 0;
}

/**
 * 插件清理函数
 */
__attribute__((visibility("default")))
void plugin_cleanup(void) {
    plugin_log(LOG_INFO, "=== 演示插件清理 ===");

    /* 输出统计信息 */
    log_statistics();

    /* 移除回调 */
    if (g_config.monitor_file_ops) {
        remove_pre_callback("open", open_pre_callback);
        remove_post_callback("open", open_post_callback);
        remove_post_callback("read", read_post_callback);
        remove_post_callback("write", write_post_callback);
    }

    if (g_config.monitor_network_ops) {
        remove_pre_callback("connect", connect_pre_callback);
        remove_post_callback("connect", connect_post_callback);
        remove_post_callback("send", send_post_callback);
        remove_post_callback("recv", recv_post_callback);
    }

    if (g_config.monitor_process_ops) {
        remove_pre_callback("execve", execve_pre_callback);
        remove_pre_callback("system", system_pre_callback);
    }

    if (g_config.monitor_memory_ops) {
        remove_post_callback("malloc", malloc_post_callback);
        remove_pre_callback("free", free_pre_callback);
    }

    plugin_log(LOG_INFO, "演示插件已清理");
} 